﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Threading;

using Gsn.Common;
using Gsn.Base;
using Gsn.Base.Notification.Calendar;


namespace Gsn.UI
{
    public class TrayIconUI : ICalendarUI
    {
        private const int BALLOON_TIMEWAIT_ = 6000;

        private volatile bool ballonVisible_;

        private bool visible_;

        private ICalendarController calendarController_;
        private NotifyIcon notifyIcon_;

        public TrayIconUI(ICalendarController calendarController)
        {
            this.CalendarController = calendarController;
            this.notifyIcon_ = new NotifyIcon();

            Icon myIcon =
                new Icon(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Gsn.UI.calendar.ico"));

            notifyIcon_.BalloonTipClosed += this.OnBalloonClose;
            notifyIcon_.BalloonTipShown += this.OnBalloonShow;
            notifyIcon_.MouseDoubleClick += this.ShowGoogleCalendarClicked;
            notifyIcon_.Icon = myIcon;
            notifyIcon_.Text = Constants.AppName;

            ContextMenuStrip menu = new ContextMenuStrip();

            menu.Items.Add("About...", null, ShowAboutForm);
            menu.Items.Add("-");
            menu.Items.Add("Change user name/password...", null, ChangeUserNamePassword);
            menu.Items.Add("-");
            menu.Items.Add("List today's events...", null, ListTodaysEventsClicked);
            menu.Items.Add("List tomorrow's events...", null, ListTomorrowsEventsClicked);
            menu.Items.Add("List this week's events...", null, ListWeeksEventsClicked);
            menu.Items.Add("-");
            menu.Items.Add("Go to my Google Calendar", null, ShowGoogleCalendarClicked);
            menu.Items.Add("-");
            menu.Items.Add("Exit", null, new EventHandler(ExitClicked));

            notifyIcon_.ContextMenuStrip = menu;
        }

        #region context menu click event handlers...

        private void ShowAboutForm(Object source, EventArgs args)
        {
            ///save current menu and unasign it...
            ContextMenuStrip menu = notifyIcon_.ContextMenuStrip;
            notifyIcon_.ContextMenuStrip = null;

            AboutForm form = new AboutForm();
            form.ShowDialog();

            ///reassign the menu...
            notifyIcon_.ContextMenuStrip = menu;
        }

        private void ChangeUserNamePassword(Object source, EventArgs args)
        {
            this.ShowCredentialsInputForm(this, null);
        }

        private void ListTodaysEventsClicked(Object source, EventArgs args)
        {
            calendarController_.ListDayCalendarEvents();
        }

        private void ListTomorrowsEventsClicked(Object source, EventArgs args)
        {
            calendarController_.ListTomorrowCalendarEvents();
        }

        private void ListWeeksEventsClicked(Object source, EventArgs args)
        {
            calendarController_.ListWeekCalendarEvents();
        }

        private void ShowGoogleCalendarClicked(Object source, EventArgs args)
        {
            System.Diagnostics.Process.Start("http://calendar.google.com/");
        }

        private void ExitClicked(Object source, EventArgs args)
        {
            Application.Exit();
        }

        #endregion

        #region IUI Members

        public IController Controller
        {
            get
            {
                return calendarController_;
            }
        }

        public bool Visible
        {
            get
            {
                return visible_;
            }

            set
            {
                visible_ = value;
                notifyIcon_.Visible = visible_;
            }
        }

        #endregion

        #region ICalendarUI Members

        public ICalendarController CalendarController
        {
            get
            {
                return calendarController_;
            }
            set
            {
                if (calendarController_ != null)
                {
                    calendarController_.ShowCredentialsInputForm -= this.ShowCredentialsInputForm;
                    calendarController_.ResetUI -= this.ResetUI;
                    calendarController_.AlarmCalendarNotification -= this.DisplayAlarmCalendarNotification;
                    calendarController_.UpdateAlarmCalendarNotification -= this.DisplayUpdateAlarmCalendarNotification;
                    calendarController_.InformativeCalendarNotification -= this.DisplayInformativeCalendarNotification;
                }

                calendarController_ = value;

                if (calendarController_ != null)
                {
                    calendarController_.ShowCredentialsInputForm += this.ShowCredentialsInputForm;
                    calendarController_.ResetUI += this.ResetUI;
                    calendarController_.AlarmCalendarNotification += this.DisplayAlarmCalendarNotification;
                    calendarController_.UpdateAlarmCalendarNotification += this.DisplayUpdateAlarmCalendarNotification;
                    calendarController_.InformativeCalendarNotification += this.DisplayInformativeCalendarNotification;
                }
            }
        }

        #endregion

        private void ShowCredentialsInputForm(Object source, EventArgs e)
        {
            ///save current menu and unasign it...
            ContextMenuStrip menu = notifyIcon_.ContextMenuStrip;
            notifyIcon_.ContextMenuStrip = null;

            CredentialsInputForm form = new CredentialsInputForm(Controller);
            form.ShowDialog();

            ///reassign the menu...
            notifyIcon_.ContextMenuStrip = menu;

            ///try to restart the engine...
            Controller.StopEngine();
            Controller.StartEngine();
        }

        private void ResetUI(Object source, EventArgs e)
        {
            notifyIcon_.Text = Constants.AppName + "\nWorking...";
        }

        private void DisplayAlarmCalendarNotification(ICalendarEngine source, CalendarNotification calendarNotification)
        {
            if (calendarNotification == null)
                return;

            CalendarNotificationHandler asyncMethod = new CalendarNotificationHandler(this.AsyncDisplayAlarmCalendarNotification);

            asyncMethod.BeginInvoke(source, calendarNotification, null, null);
        }

        private void DisplayUpdateAlarmCalendarNotification(ICalendarEngine source, CalendarNotification calendarNotification)
        {
            if (calendarNotification == null)
                return;

            if(calendarNotification.Count == 0)
                notifyIcon_.Text = Constants.AppName + "\nThere are no incoming events.";
            else
                notifyIcon_.Text = Constants.AppName + "\n" + calendarNotification.ElementAt(0).Title + " will be at " + calendarNotification.ElementAt(0).StartDateTime;

            DisplayInformativeCalendarNotification(source, calendarNotification);
        }

        private void DisplayInformativeCalendarNotification(ICalendarEngine source, CalendarNotification calendarNotification)
        {
            if (calendarNotification == null)
                return;

            CalendarNotificationHandler asyncMethod = new CalendarNotificationHandler(this.AsyncDisplayInformativeCalendarNotification);

            asyncMethod.BeginInvoke(source, calendarNotification, null, null);
        }

        private void AsyncDisplayAlarmCalendarNotification(ICalendarEngine source, CalendarNotification calendarNotification)
        {
            foreach (CalendarNotificationElement calendarNotificationElement in calendarNotification)
            {
                MessageBox.Show(
                    calendarNotificationElement.Title + "\n\n" +
                    "Start time:\t" + calendarNotificationElement.StartDateTime + "\n" +
                    "End time:\t" + calendarNotificationElement.EndDateTime + "\n\n" +
                    "Description (if any):\n" + calendarNotificationElement.Description,
                    "Event alarm!!! (current time is " + DateTime.Now + ")",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Information,
                    MessageBoxDefaultButton.Button1,
                    MessageBoxOptions.ServiceNotification);
            }
        }

        private void AsyncDisplayInformativeCalendarNotification(ICalendarEngine source, CalendarNotification calendarNotification)
        {
            String content;
            DateTime timeout;

            if (calendarNotification.Count == 0)
            {
                content = "There are no incoming events.";
                notifyIcon_.ShowBalloonTip(BALLOON_TIMEWAIT_, calendarNotification.Title, content, ToolTipIcon.Info);
            }
            else
            {
                int i = 1;
                foreach (CalendarNotificationElement calendarNotificationElement in calendarNotification)
                {
                    content = "\n";
                    content += calendarNotificationElement.Title + "\n\n";
                    content += "Start time:\t" + calendarNotificationElement.StartDateTime + "\n";
                    content += "End time:\t" + calendarNotificationElement.EndDateTime + "\n\n";
                    content += "Description (if any):\n" + calendarNotificationElement.Description + "\n";

                    notifyIcon_.ShowBalloonTip(BALLOON_TIMEWAIT_, calendarNotification.Title + " (" + (i++) + "/" + calendarNotification.Count + ")",
                        content, ToolTipIcon.Info);

                    timeout = DateTime.Now.AddMilliseconds(BALLOON_TIMEWAIT_);;
                    while (ballonVisible_ && timeout > DateTime.Now)
                        Thread.Sleep(100);
                }
            }
        }

        private void OnBalloonClose(Object source, EventArgs args)
        {
            ballonVisible_ = false;
        }

        private void OnBalloonShow(Object source, EventArgs args)
        {
            ballonVisible_ = true;
        }
    }
}

